#pragma once
#include<queue>
#include<pthread.h>
#include<iostream>
#include "Task.hpp"
#include "LockGuard.hpp"

namespace wyl
{
  
    #define DEFAULT_NUM 5
    template<class T>
    class block_queue
    {
    private:
        size_t _num;
        std::queue<T> _blockqueue; 
        pthread_mutex_t _mtx; 
        pthread_cond_t _full; 
        pthread_cond_t _empty; 

    public: 
        block_queue(size_t num = DEFAULT_NUM) : _num(num){
            pthread_mutex_init(&_mtx,nullptr);
            pthread_cond_init(&_full,nullptr);
            pthread_cond_init(&_empty,nullptr);
        }
        ~block_queue()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_full);
            pthread_cond_destroy(&_empty);
        }

        //生产者生产
        void Push(const T& task)
        {
            LockGuard lockguard(&_mtx);
            while(isfull()) Wait(&_full); //生产队列已满，生产者进入等待 
            //被唤醒后添加任务到生产队列
            _blockqueue.push(task);
            printf("%p 生产了一个任务 : %d %c %d\n",pthread_self(),task._x,task._op,task._y);
            Wakeup(&_empty); //唤醒消费者
        }

        // 消费者消费
        void Pop(T* out)
        {
            LockGuard lockguard(&_mtx) ;
            while(isempty()) Wait(&_empty); //生产队列已空，消费者进入等待 
            //被唤醒后添加任务到生产队列
            *out = _blockqueue.front();
            _blockqueue.pop();
            Wakeup(&_full);
        }
        private:
            void Wait(pthread_cond_t* cond) {pthread_cond_wait(cond,&_mtx);}
            void Wakeup(pthread_cond_t* cond) {pthread_cond_signal(cond);}
            bool isfull() { return _blockqueue.size() == _num;}
            bool isempty() { return _blockqueue.size() == 0;}
    };

};


